#include "textures.h"
#include <IL/il.h>
#include <cstdlib>
#include <cmath>
#include "mtxlib.h"

#pragma comment(lib, "devil.lib")

namespace Textures 
{

float lod_bias = .0f;			// Represents value from -5 to 5 that is bound to middle mouse button and then used to set mipmap lod bias

GLuint	tex_light_cookie = 0,	// spot light image
		tex_light_att = 0,		// distance attenuation texture
		tex_wood = 0,			// floor texture  - procedurally generated
		tex_carpet = 0,			// carpet texture
		tex_poster = 0,			// poster texture - "lautrec_divan.jpg"
		tex_bricks = 0,			// bricks texture - "brick_wall.jpg"
		tex_perlin = 0,			// noise texture  - "perlin.jpg"
		tex_smoke = 0,			// smoke puff texture - "smoke.PNG"
		tex_smokecolors = 0,	// smoke color texture - "smokecolors.PNG"
		tex_reflect = 0,		// viewport copy of reflected scene
		tex_screen = 0;			// viewport copy
		

void empty_texture(GLuint &tex, int w, int h)
{
	if (tex>0)
		glDeleteTextures(1, &tex);
	glGenTextures(1, &tex);
	glBindTexture(GL_TEXTURE_2D, tex);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
}

void load_texture(GLuint &tex, const char *filename)
{
	glGenTextures(1, &tex);
	glBindTexture(GL_TEXTURE_2D, tex);
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
	glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);

	ILuint ImgId;
	ilInit ();
	ilGenImages(1, &ImgId);
	ilBindImage(ImgId);
	ILboolean success = ilLoadImage(filename);
	if (success)
	{
		ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE);
		GLint internalFormat = ilGetInteger(IL_IMAGE_BPP);
		GLsizei width = ilGetInteger(IL_IMAGE_WIDTH), height = ilGetInteger(IL_IMAGE_HEIGHT);
		GLenum format = ilGetInteger(IL_IMAGE_FORMAT);
		glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, ilGetData());
	}
	ilDeleteImages(1, &ImgId);
}

void make_wood()
{
	const int size = 512;
	const int tilew = 16;
	const int tileh = 64;
	const int maxx = size-tilew;
	const int maxy = size-tileh;

	int w;
	int h;
	int components;
	unsigned char *data0;
//	img::read("media/perlin.jpg", &w, &h, &data0, &components);

	ILuint ImgId;
	ilInit ();
	ilGenImages(1, &ImgId);
	ilBindImage(ImgId);
	ILboolean success = ilLoadImage("media/perlin.jpg");
	if (success)
	{
		ilConvertImage(IL_RGB, IL_UNSIGNED_BYTE);
		w = (int)ilGetInteger(IL_IMAGE_WIDTH);
		h = (int)ilGetInteger(IL_IMAGE_HEIGHT);
		components = ilGetInteger(IL_IMAGE_FORMAT)==GL_RGB?3:4;
		data0 = ilGetData();
	}

	empty_texture(tex_wood, size, size);

	struct 
	{
		int x,y;
		float d;
	} tab[8][32];
	for (int i = 0; i < 8; ++i)
	for (int j = 0; j < 32; ++j)
	{
		tab[i][j].x = rand()%maxx;
		tab[i][j].y = rand()%maxy;
		tab[i][j].d = 0.7f+0.3f*static_cast<float>(rand())/static_cast<float>(RAND_MAX);
	}
	
	unsigned *data = new unsigned[size * size];
	for (int y = 0; y < size; ++y)
	for (int x = 0; x < size; ++x)
	{
		int x0 = x, y0 = y;
		y = (y+(x/tilew)*tilew)%size;
		int ix = x / tilew;
		int iy = y / tileh;
		x = tab[iy][ix].x+(x%tilew);
		y = tab[iy][ix].y+(y%tileh);
		float noise = (data0[(y*w+x)*components]) / 255.0f;
		float radius = sqrtf((x-0.5f*size)*(x-0.5f*size)+(y-0.5f*size)*(y-0.5f*size))/(0.5f*size);
		radius = 200.0f * radius + 12.0f * noise;
		float t = 0.5f*(cosf(radius)+1.0f);

		vector4 c0 = vector4(1.0f,0.85f,0.6f,1.0f);
		vector4 c1 = vector4(0.8f,0.7f,0.45f,1.0f);
		vector4 c = c1*(1-t)+c0*t;
		c *= tab[iy][ix].d;

		data[(size-1-y0)*size+x0] = 
			(unsigned)((static_cast<unsigned>(c.z*255.0f)<<16)|(static_cast<unsigned>(c.y*255.0f)<<8)|(static_cast<unsigned>(c.x*255.0f)<<0)|0xff000000);
		x = x0;
		y = y0;
	}
		
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
	delete[] data;

	ilDeleteImages(1, &ImgId);
}

void init()
{
	load_texture(tex_light_cookie, "media/light_cookie.PNG");
	load_texture(tex_light_att, "media/light_att.PNG");
	load_texture(tex_poster, "media/lautrec_divan.jpg");
	load_texture(tex_bricks, "media/brick_wall.jpg");
	load_texture(tex_smoke, "media/smoke.PNG");
	load_texture(tex_smokecolors, "media/smokecolors.PNG");
	load_texture(tex_perlin, "media/perlin.jpg");
	load_texture(tex_carpet, "media/carpet.jpg");
	make_wood();
}

void done()
{
	glDeleteTextures(1, &tex_light_cookie);
	glDeleteTextures(1, &tex_light_att);
	glDeleteTextures(1, &tex_poster);
	glDeleteTextures(1, &tex_bricks);
	glDeleteTextures(1, &tex_smoke);
	glDeleteTextures(1, &tex_smokecolors);
	glDeleteTextures(1, &tex_perlin);
	glDeleteTextures(1, &tex_wood);
	glDeleteTextures(1, &tex_reflect);
	glDeleteTextures(1, &tex_screen);
}

}